package com.x.ant.util;

import com.google.gson.GsonBuilder;
import com.x.framework.model.BaseObject;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestClientFactory;
import io.searchbox.client.JestResult;
import io.searchbox.client.config.HttpClientConfig;
import io.searchbox.core.*;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.mapping.GetMapping;
import io.searchbox.indices.mapping.PutMapping;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;

import java.util.ArrayList;
import java.util.List;

public class JestFactory {
	private static final Logger logger = LogManager.getLogger(JestFactory.class);

	private static JestClientFactory factory;
	private static JestClient jestClient;
	private static List<String> nodes = new ArrayList<String>();
	private static int connTimeOut;
	private static int readTimeOut;

	public JestFactory(String nodes, int connTimeOut, int readTimeOut) {
		String[] nodeArray = nodes.split(",");
		for (String node : nodeArray) {
			this.nodes.add(node);
		}
		this.connTimeOut = connTimeOut;
		this.readTimeOut = readTimeOut;
		jestClient = this.getJestClient();
	}

	/**
	 * 获取JestClient对象
	 *
	 * @return
	 */
	private static JestClient getJestClient() {
		if(jestClient == null){
			factory = new JestClientFactory();
			factory.setHttpClientConfig(new HttpClientConfig
					.Builder(nodes)
					.gson(new GsonBuilder().setDateFormat("yyyy-MM-dd'T'hh:mm:ss").create())
					.connTimeout(connTimeOut)
					.readTimeout(readTimeOut)
					.multiThreaded(true)
					.build());
			jestClient = factory.getObject();
		}
		return jestClient;
	}

	/**
	 * 关闭JestClient客户端
	 *
	 * @param jestClient
	 * @throws Exception
	 */
	public void closeJestClient() {
		if (jestClient != null) {
			jestClient.shutdownClient();
		}
	}
	/**
	 * 创建索引
	 *
	 * @param jestClient
	 * @param index
	 * @return
	 * @throws Exception
	 */
	public boolean createIndex(String index) {
		boolean flag = false;
		try {
			Settings.Builder settingsBuilder = Settings.builder();
			settingsBuilder.put("number_of_shards", 1);
			settingsBuilder.put("number_of_replicas", 1);
			settingsBuilder.put("index.analysis.filter.synonym_filter.type", "synonym");
			settingsBuilder.put("index.analysis.filter.synonym_filter.synonyms_path", "synonym.txt");
			settingsBuilder.put("index.analysis.filter.synonym_filter.ignore_case", true);
			settingsBuilder.put("index.analysis.filter.pinyin_filter.type", "pinyin");
			settingsBuilder.put("index.analysis.filter.pinyin_filter.first_letter", "prefix");
			settingsBuilder.put("index.analysis.filter.pinyin_filter.padding_char", " ");
			settingsBuilder.put("index.analysis.analyzer.ik_pinyin_synonym_analyzer.type", "custom");
			settingsBuilder.put("index.analysis.analyzer.ik_pinyin_synonym_analyzer.tokenizer", "ik_smart");
			settingsBuilder.put("index.analysis.analyzer.ik_pinyin_synonym_analyzer.filter.0", "synonym_filter");
			settingsBuilder.put("index.analysis.analyzer.ik_pinyin_synonym_analyzer.filter.1", "pinyin_filter");
			settingsBuilder.put("index.analysis.analyzer.ik_pinyin_synonym_analyzer.filter.2", "word_delimiter");
			JestResult jr = getJestClient().execute(new CreateIndex.Builder(index).settings(settingsBuilder.build().getAsMap()).build());
			flag = jr.isSucceeded();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			return flag;
		}
	}

    public static boolean createIndexMapping(String index, String type, String source) throws Exception {
		PutMapping putMapping = new PutMapping.Builder(index, type, source).build();
		JestResult jr = getJestClient().execute(putMapping);
		return jr.isSucceeded();
	}

	/**
	 * Get映射
	 *
	 * @param jestClient
	 * @param index
	 * @param type
	 * @return
	 * @throws Exception
	 */
	public String getIndexMapping(String index, String type) throws Exception {
		GetMapping getMapping = new GetMapping.Builder().addIndex(index).addType(type).build();
		JestResult jr = getJestClient().execute(getMapping);
		return jr.getJsonString();
	}

	/**
	 * 索引文档
	 *
	 * @param jestClient
	 * @param index
	 * @param type
	 * @param objs
	 * @return
	 * @throws Exception
	 */
	public <T extends BaseObject> boolean addDocs(String index, String type, List<T> objs) throws Exception {
		Bulk.Builder builder = new Bulk.Builder().defaultIndex(index).defaultType(type);
		builder.refresh(true);
		for (Object obj : objs) {
			Index i = new Index.Builder(obj).build();
			builder.addAction(i);
		}
		BulkResult br = getJestClient().execute(builder.build());
		return br.isSucceeded();
	}

	/**
	 * 搜索文档
	 *
	 * @param jestClient
	 * @param index
	 * @param type
	 * @param query
	 * @return
	 * @throws Exception
	 */
	private SearchResult search(String index, String type, String query) throws Exception {
		Search search = new Search.Builder(query).addIndex(index).addType(type).build();
		return getJestClient().execute(search);
	}

	/**
	 * Count文档
	 *
	 * @param jestClient
	 * @param index
	 * @param type
	 * @param query
	 * @return
	 * @throws Exception
	 */
	public Double count(String index, String type, QueryBuilder queryBuilder) throws Exception {
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.query(queryBuilder);
		String query = searchSourceBuilder.toString();
		Count count = new Count.Builder().addIndex(index).addType(type).query(query).build();
		CountResult results = getJestClient().execute(count);
		if(results != null) {
			return results.getCount();
		} else {
			return Double.valueOf(0);
		}
	}

	/**
	 * Get文档
	 *
	 * @param jestClient
	 * @param index
	 * @param type
	 * @param id
	 * @return
	 * @throws Exception
	 */
	public JestResult get(String index, String type, String id) throws Exception {
		Get get = new Get.Builder(index, id).type(type).build();
		return getJestClient().execute(get);
	}

	/**
	 * Delete索引
	 *
	 * @param jestClient
	 * @param index
	 * @return
	 * @throws Exception
	 */
	public boolean deleteIndex(String index) throws Exception {
		JestResult jr = getJestClient().execute(new DeleteIndex.Builder(index).build());
		return jr.isSucceeded();
	}

	/**
	 * Delete文档
	 *
	 * @param jestClient
	 * @param index
	 * @param type
	 * @param id
	 * @return
	 * @throws Exception
	 */
	public boolean deleteDoc(String index, String type, String id) throws Exception {
		DocumentResult dr = getJestClient().execute(new Delete.Builder(id).index(index).type(type).build());
		return dr.isSucceeded();
	}

	public <T extends BaseObject> List<T> matchQuery(String index, String type, String filed, String keyword, int pageIndex, int pageSize, Class<T> clazz) throws Exception {
		List<T> list = new ArrayList<T>();
		QueryBuilder queryBuilder = QueryBuilders.matchQuery(filed, keyword);// 模糊匹配查询
		queryBuilder.boost();
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.query(queryBuilder);
		searchSourceBuilder.from(pageIndex);
		searchSourceBuilder.size(pageSize);
		String query = searchSourceBuilder.toString();
        logger.info(query);
		SearchResult result = this.search(index, type, query);
		if (result != null) {
			List<SearchResult.Hit<T, Void>> hits = result.getHits(clazz);
			if(hits != null && hits.size() > 0) {
				for (SearchResult.Hit<T, Void> hit : hits) {
					T t = hit.source;
					list.add(t);
				}
			}
		}
		return list;
	}

    public <T extends BaseObject> List<T> multiMatchQuery(String index, String type, BoolQueryBuilder boolQueryBuilder, int pageIndex, int pageSize, Class<T> clazz) throws Exception {
//        QueryBuilder keywordQueryBuilder = QueryBuilders.multiMatchQuery(keyword, fileds);// 模糊匹配查询
//        QueryBuilder districtQueryBuilder = QueryBuilders.termQuery("districtId", districtId);
//        QueryBuilder partIdQueryBuilder = QueryBuilders.termQuery("partId", partId);
//        QueryBuilder queryFilter = QueryBuilders.boolQuery().must(keywordQueryBuilder).must(districtQueryBuilder).must(partIdQueryBuilder);
        boolQueryBuilder.boost();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.from(pageIndex);
        searchSourceBuilder.size(pageSize);
        String query = searchSourceBuilder.toString();
        logger.info(query);
        SearchResult result = this.search(index, type, query);
        List<T> list = new ArrayList<T>();
        if (result != null) {
            List<SearchResult.Hit<T, Void>> hits = result.getHits(clazz);
			if(hits != null && hits.size() > 0) {
                logger.info("Size:" + hits.size());
                for (SearchResult.Hit<T, Void> hit : hits) {
					T t = hit.source;
					list.add(t);
				}
			}
        }
        return list;
    }

    public int multiMatchCount(String index, String type, BoolQueryBuilder boolQueryBuilder) throws Exception {
        boolQueryBuilder.boost();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder);
        String query = searchSourceBuilder.toString();
        logger.info(query);
        SearchResult result = this.search(index, type, query);
        logger.info(result.getTotal());
		if (result != null) {
			return result.getTotal();
		} else {
			return 0;
		}
    }

    public static void main(String[] arg) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        String keyword = "xxxx";
        String districtId = null;
        Integer partId = 1;
        if(keyword != null) {
            boolQueryBuilder.must(QueryBuilders.multiMatchQuery("xxx", "estateName", "estateAlias", "estateAddress"));
        }
        if(districtId != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery("districtId", ""));
        }
        if(partId != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery("partId", 1));
        }
        boolQueryBuilder.boost();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.from(1);
        searchSourceBuilder.size(10);
        String query = searchSourceBuilder.toString();
        logger.info(query);
    }

}
